/*
 * fs.c
 *
 *  Created on: 2016-11-17
 *      Author: m
 */
#include "fs.h"
#include "proc.h"
#include "ipc_type.h"
#include "hd.h"
#include "string.h"
#include "drv_def.h"
#include "global.h"
#include "fcntl.h"

static PART_INFO s_geo_info = {0};
static SUPPER_BLOCK s_sb = {0};
static char s_inode_map[512] = {0};

static void get_part_geometry(PART_INFO* pi) {
    MESSAGE msg;
    CPT(MT_HD_IO_CTRL_TYPE*, msg.data)->minor = BOOT_MINOR;
    msg.type = MT_HD_IO_CTRL;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
    *pi = CPT(MT_HD_IO_CTRL_TYPE*, msg.data)->pi;
    printf("hd geometry start_sect=%d(s_sb.0x%x), cnt=%d\n", pi->start_sect, (pi->start_sect + 1) * 512, pi->num_sect);
}
static void mk_supper_block(u32 part_sect_cnt) {
    char buf[512] = {0};
    MESSAGE msg;
    MT_HD_RW_TYPE* p = (MT_HD_RW_TYPE*)msg.data;

    s_sb.magic = 0x7A9E;
    s_sb.fs_version = 0x0100;
    s_sb.inode_cnt = 512 * 8; //这里固定用一个扇区表示哪些inode有效，所以其最多有512*8=4096个inode
    s_sb.sect_cnt = part_sect_cnt;  //BOOT_MINOR所在分区的扇区数,这里为40257
    s_sb.inode_map_sect_cnt = 1; //inode_cnt的注释已经写过了,这里固定为1                               关键点：标示哪些inode有效
    s_sb.sect_map_sect_cnt = (part_sect_cnt + 4095) / 4096;  //用一个bit位来表示一个扇区是否被使用，因此有 (40257 + 4095)/(512*8)=10  关键点：标示哪些扇区有效
    s_sb.inode_arr_sect_cnt = (4096 * sizeof(INODE) + 511) / 512; //(4096*sizeof(inode)+511)/512=(4096*32+511)/512=256
    s_sb.idx_1st_data_sect = 1 + 1 + s_sb.inode_map_sect_cnt + s_sb.sect_map_sect_cnt + s_sb.inode_arr_sect_cnt; //第一个数据扇区的索引=sect_cnt(boot)+sect_cnt(sb)+sect_cnt(inode-map)+sect_cnt(sect_map)+sect_map(inode_arr)=1+1+1+10+256=269
    s_sb.idx_root_inode = 1; //固定为1
    s_sb.inode_size = sizeof(INODE); //固定为32
    memcpy(buf, &s_sb, sizeof(s_sb));

    msg.type = MT_HD_WRITE;
    p->buf = buf;
    p->from_pid = TASK_IDX_FS;
    p->minor = BOOT_MINOR;
    p->pos = 1 * 512;
    printf("sb@0x%x\n", s_geo_info.start_sect * 512 + p->pos);
    p->rw_len = 512;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
}

static void mk_inode_map_sect() {
    char buf[512] = {0};
    MESSAGE msg;
    MT_HD_RW_TYPE* p = (MT_HD_RW_TYPE*)msg.data;

    buf[0] = 0x1F; //bit0:reserved bit1:root-inode bit2-4:tty0-2
    msg.type = MT_HD_WRITE;
    p->buf = buf;
    p->from_pid = TASK_IDX_FS;
    p->minor = BOOT_MINOR;
    p->pos = 2 * 512;
    printf("inode-map@0x%x\n", s_geo_info.start_sect * 512 + p->pos);
    p->rw_len = 512;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
}

static void mk_sect_map() {
    char buf[512] = {0};
    MESSAGE msg;
    MT_HD_RW_TYPE* p = (MT_HD_RW_TYPE*)msg.data;

    for(int i = 0; i < (2048 + 1) / 8; ++i) {
        buf[i] = 0xFF;
    }
    buf[256] = 0x1;

    msg.type = MT_HD_WRITE;
    p->buf = buf;
    p->from_pid = TASK_IDX_FS;
    p->minor = BOOT_MINOR;
    p->pos = 3 * 512;
    printf("sect-map@0x%x\n", s_geo_info.start_sect * 512 + p->pos);
    p->rw_len = 512;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);

    memset(buf, 0, 512);
    for(int i = 1; i < s_sb.sect_map_sect_cnt; ++i) {
        p->pos = (3 + i) * 512;
        post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
    }
}

static void mk_node_array() {
    char buf[512] = {0};
    MESSAGE msg;
    MT_HD_RW_TYPE* p = (MT_HD_RW_TYPE*)msg.data;
    INODE* pin = (INODE*)buf;
    pin[0].access_mode = I_DIRECTORY; // root(/)
    pin[0].data_start_sect = s_sb.idx_1st_data_sect;
    pin[0].data_sect_cnt = 2048;
    pin[0].file_size = sizeof(DIR_ENTRY) * 4; // 4 files: . tty0-2

    pin[1].access_mode = I_CHAR_SPECIAL; // tty0
    pin[1].data_start_sect = MAKE_DEV_NO(MAJ_DEV_TTY, 0);
    pin[1].data_sect_cnt = 0;
    pin[1].file_size = 0;

    pin[2].access_mode = I_CHAR_SPECIAL; // tty1
    pin[2].data_start_sect = MAKE_DEV_NO(MAJ_DEV_TTY, 1);
    pin[2].data_sect_cnt = 0;
    pin[2].file_size = 0;

    pin[3].access_mode = I_CHAR_SPECIAL; // tty2
    pin[3].data_start_sect = MAKE_DEV_NO(MAJ_DEV_TTY, 2);
    pin[3].data_sect_cnt = 0;
    pin[3].file_size = 0;

    msg.type = MT_HD_WRITE;
    p->buf = buf;
    p->from_pid = TASK_IDX_FS;
    p->minor = BOOT_MINOR;
    p->pos = (3 + s_sb.sect_map_sect_cnt) * 512;
    printf("inode-arr@0x%x\n", s_geo_info.start_sect * 512 + p->pos);
    p->rw_len = 512;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);

    memset(buf, 0, 512);
    for(int i = 1; i < s_sb.inode_arr_sect_cnt; ++i) {
        p->pos = (3 + s_sb.sect_map_sect_cnt + i) * 512;
        post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
    }
}

static void mk_entry() {
    char buf[512] = {0};
    MESSAGE msg;
    MT_HD_RW_TYPE* p = (MT_HD_RW_TYPE*)msg.data;
    DIR_ENTRY* pe = (DIR_ENTRY*)buf;

    strcpy(pe[0].name, ".");
    pe[0].inode_idx = 1; //0保留
    strcpy(pe[1].name, "dev-tty0");
    pe[0].inode_idx = 2;
    strcpy(pe[2].name, "dev-tty1");
    pe[0].inode_idx = 3;
    strcpy(pe[3].name, "dev-tty2");
    pe[0].inode_idx = 4;

    msg.type = MT_HD_WRITE;
    p->buf = buf;
    p->from_pid = TASK_IDX_FS;
    p->minor = BOOT_MINOR;
    p->pos = (3 + s_sb.sect_map_sect_cnt + s_sb.inode_arr_sect_cnt) * 512;
    printf("entry-arr@0x%x\n", s_geo_info.start_sect * 512 + p->pos);
    p->rw_len = 512;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
}

static int mkfs() {
    get_part_geometry(&s_geo_info);
    mk_supper_block(s_geo_info.num_sect);
    mk_inode_map_sect();
    mk_sect_map();
    mk_node_array();
    mk_entry();
    return 0;
}

void init_fs() {
    MESSAGE msg;
    MT_DEV_OPEN_TYPE* p = (MT_DEV_OPEN_TYPE*)msg.data;
    p->minor = BOOT_MINOR;
    msg.type = MT_DEV_OPEN;
    post(FN_BOTH, TASK_IDX_HD_DRV, &msg);
    mkfs();
}

static int get_free_desc_in_proc_table_item(PROCESS* p) {
    for(int i = 0; i < PROC_FD_MAX; ++i) {
        if(0 == p->fd_arr[i]) {
            return i;
        }
    }
    return -1;
}
static int get_free_desc_in_g_fd() {
    for(int i = 0; i < FILE_DESC_MAX; ++i) {
        if(0 == g_fd_table[i].pi) {
            return i;
        }
    }
    return -1;
}

//found:ret idx, not found:ret 0
static int search_file(char* full_path) {
    return 0;
}

//ret:new inode's index
static int alloc_inode_map_bit(int dev_minor) {

}

static INODE* create_file(const char* full_path, int flgs) {
    return 0;
}

static int do_open(MESSAGE* msg) {
    MT_FS_OPEN_TYPE* p = (MT_FS_OPEN_TYPE*)msg->data;
    PROCESS* req = &g_proc_table[msg->req_pid];
    int fd = get_free_desc_in_proc_table_item(req);
    if(fd < 0) return -1;

    int fd_g = get_free_desc_in_g_fd();
    if(fd_g < 0) return -2;

    int inode_idx = search_file(p->path); //todo copy to self mem-space
    INODE* pi = 0;
    if(p->flags & O_CREATE) {
        if(inode_idx) {
            printf("%s, file existed!", p->path);
            return -3;
        }
        pi = create_file(p->path, p->flags);
    } else {
        //todo
    }

    if(!pi) return -4;
    req->fd_arr[fd] = &g_fd_table[fd_g];
    g_fd_table[fd_g].pi = pi;
    g_fd_table[fd_g].fd_mode = p->flags;
    g_fd_table[fd_g].fd_cur_rw_pos = 0;

    return fd;
}

void task_fs() {
    //init_fs();
    while(1) {
        MESSAGE msg;
        post(FN_RECV, TASK_ANY, &msg);
        switch(msg.type) {
        case MT_FS_OPEN:
            CPT(MT_FS_OPEN_TYPE*, msg.data)->fd = do_open(&msg);
            break;
        case MT_FS_CLOSE:
            break;
        }
        //msg.type = MT_SYSCAL_RET;
        post(FN_SEND, msg.req_pid, &msg);
    }
}



